<template>
  <div class="webSocket">
   <div>
     <div style="display: flex">
       <h2 style="margin-right: 10px">webSocket(多对多群聊)</h2>
       <el-button type="primary" @click="WebSocketConnect" :disabled="isConnect">建立连接</el-button>
       <el-button @click="closeWebSocket" type="danger" :disabled="!isConnect">关闭连接</el-button>
     </div>
     <br>
     <div class="messageBody">
       <div class="messageBox" ref="messageBoxRef">
         <div class="messageItem" v-for="item in webSocketInfo" :class="item.account === user.account ? 'infoRight' : 'infoLeft'">
           <div class="infoHalf" :class="item.account === user.account ? 'infoHalfRight' : 'infoHalfLeft'">
             <div class="messageBlock" :class="item.msg_type === 'delete' ? 'delete_msg' : ''" v-if="item.account === user.account" @contextmenu="contextmenu($event, item)">
               <span v-if="item.msg_type === 'delete'" v-html="item.message" class="msgHtml"></span>
               <el-popover
                   v-else
                   placement="right"
                   :width="100"
                   trigger="contextmenu"
               >
                 <template #default>
                   <div class="withdrawClass" @click="withdraw(item)">
                     撤回
                   </div>
                 </template>
                 <template #reference>
                   <span v-html="item.message" class="msgHtml"></span>
                 </template>
               </el-popover>
             </div>
             <img :src="item.src" class="img"/>
             <div class="messageBlock" :class="item.msg_type === 'delete' ? 'delete_msg' : ''" v-if="item.account !== user.account" @contextmenu="contextmenu($event, item)">
               <span v-if="item.msg_type === 'delete'" v-html="item.message" class="msgHtml"></span>
               <el-popover
                   v-else
                   placement="right"
                   :width="100"
                   trigger="contextmenu"
               >
                 <template #default>
                   <div class="withdrawClass" @click="withdraw(item)">
                     撤回
                   </div>
                 </template>
                 <template #reference>
                   <span v-html="item.message" class="msgHtml"></span>
                 </template>
               </el-popover>
             </div>
           </div>
         </div>
       </div>
       <div class="messageInput">
         <div style="display: none;">
           <el-input ref="inputRef" v-model="userInput"
                     type="textarea"
                     style="width: 540px;" @keyup.enter="postMsg(userInput)"></el-input>
           <el-button type="primary" :disabled="!wsRef" @click="postMsg(userInput)" size="small" style="margin-left: 10px">发送</el-button>
         </div>
         <div style="display: flex;align-items: end;">
           <WangEditor :modelValue="infoRef" :toolbarConfig="toolbarConfig" @handleChange="handleChange" class="wangEditor"></WangEditor>
           <el-button type="primary" :disabled="!wsRef" @click="editPostMsg" size="small" class="mt10" style="margin-left: 10px">发送</el-button>
         </div>
       </div>
     </div>
   </div>
    <div style="margin-left: 16px">
      <div style="display: flex">
        <h2 style="margin-right: 10px">worker子线程</h2>
        <el-button type="primary" @click="newWorker" :disabled="!!worker">建立worker连接</el-button>
        <el-button type="danger" @click="closeWorker" :disabled="!worker">关闭worker连接</el-button>
      </div>
      <br>
      <div class="workerBox">
        <p>主线程</p>
        <div class="mainThread">
          <el-input v-model="workerInput" style="width: 200px"></el-input>
          <el-button type="primary" @click="postWorker('')" size="small" style="margin-left: 10px" :disabled="!worker">传递消息给子线程</el-button>
        </div>
        <br>
        <p>主线程收到子线程处理后的数据</p>
        <div class="subThread">
          <span v-html="ThreadGet"></span>
        </div>
        <br>
        <div style="display: flex;align-items: center">
          <p>主线程收到子线程异步处理后的数据</p>
          <el-button type="primary" @click="postWorker('async')" style="margin-left: 10px" size="small" :disabled="!worker">异步操作（/testq请求）</el-button>
        </div>
        <div class="asyncAction" v-loading="asyncLoading">
          <span v-html="asyncGet"></span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import {computed, nextTick, onMounted, ref} from "vue";
import {ElMessage, ElMessageBox} from "element-plus";
import {useGlobalProperties} from "../../hooks/globalVar.js";
let {DeploymentAddress} = useGlobalProperties()
import WangEditor from "@/components/WangEditor";

const user = JSON.parse(localStorage.getItem('user'))
// WebSocket
let wsRef = ref(null)
let webSocketInfo = ref([])
let userInput = ref('')
let inputRef = ref(null)
let isConnect = ref(false)
let messageBoxRef = ref(null)
let infoRef = ref('')
let toolbarConfig = {
  excludeKeys: [],
  toolbarKeys: [
    "emotion",
    "uploadImage",
    "bold",
    "italic",
    "code",
    "color",
    "bgColor",
    "fontSize",
    "fontFamily",
    "fullScreen",
  ]
}

function WebSocketConnect() {
  let params = {
    opType: "chat",
    account: user.account
  }
  let paramsString = new URLSearchParams(params).toString()
  let socketUrl = process?.env?.NODE_ENV === 'development' ? ("ws://127.0.0.1:6789?" + paramsString) : (`ws://${DeploymentAddress}:6789?` + paramsString)
  // 打开一个 websocket
  wsRef.value = new WebSocket(socketUrl);
  wsRef.value.onopen = function () {
    // Web Socket 已连接上，使用 send() 方法发送数据
    isConnect.value = true
  }
  wsRef.value.onmessage = function (evt) {
    webSocketInfo.value = eval(evt.data)
    nextTick(() => {
      setScrollToBottom()
    })
  }
  wsRef.value.onclose = function () {
    // 关闭 websocket
    isConnect.value = false
    webSocketInfo.value.push({
      account: user.account,
      message: "连接已关闭...",
    })
    nextTick(() => {
      setScrollToBottom()
    })
  }
  wsRef.value.onerror = function () {
    // 通信发生错误，关闭 websocket
    isConnect.value = false
    webSocketInfo.value.push({
      account: user.account,
      message: '通信发生错误...',
    })
    nextTick(() => {
      setScrollToBottom()
    })
  }
}
function closeWebSocket() {
  wsRef.value.close()
}
function postMsg(value) {
  if (!isConnect.value) return ElMessage.error('离线了！')
  let postMsg = {
    account: user.account,
    time: $('#nowTime')[0].innerHTML,
    message: value
  }
  wsRef.value.send(JSON.stringify(postMsg));
  nextTick(() => {
    userInput.value = ''
  })
}
function withdraw(item) {
  wsRef.value.send(JSON.stringify(item))
}
function contextmenu(event, item) {
  event.preventDefault();
}
function setScrollToBottom() {
  if (messageBoxRef.value) messageBoxRef.value.scrollTop = messageBoxRef.value?.scrollHeight
}

function handleChange(html, editor) {
  infoRef.value = editor.getHtml()
}
function editPostMsg() {
  if (!isConnect.value) return ElMessage.error('离线了！')
  let postMsg = {
    account: user.account,
    time: $('#nowTime')[0].innerHTML,
    message: infoRef.value
  }
  wsRef.value.send(JSON.stringify(postMsg));
  nextTick(() => {
    infoRef.value = ''
  })
}

//worker线程
let worker = ref('')
let workerInput = ref('')
let ThreadGet = ref('')
let asyncGet = ref('')
let asyncLoading = ref(false)
function newWorker() {
  worker.value = new Worker(new URL('./webSocketWorker.js', import.meta.url))
  worker.value.onmessage = (e) => {
    if (e.data.type === 'async') {
      asyncGet.value = e.data.data
      asyncLoading.value = false
    } else {
      ThreadGet.value = e.data.data
    }
  }
  worker.value.onerror = (e) => {
    console.error(e)
    worker.value = null
  }
}
function closeWorker() {
  if (worker.value) worker.value.terminate()
  worker.value = null
}
function postWorker(type) {
  asyncLoading.value = type === 'async'
  if (worker.value) worker.value.postMessage(type ? type : workerInput.value)
}

onMounted(() => {
  WebSocketConnect()
  setScrollToBottom()
})

</script>

<style scoped lang="less">
.webSocket {
  display: flex;
  padding: 16px;
}
.messageBody {
  width: 600px;
  .messageBox {
    width: 100%;
    height: 250px;
    overflow: auto;
    border: 1px solid #e3e3e3;
    position: relative;
    .messageItem {
      width: 100%;
      min-height: 30px;
      line-height: 1.5;
      margin: 10px 0;
      .messageBlock {
        max-width: 80%;
        padding: 5px;
        background-color: #b3ecf8;
        border-radius: 3px;
        position: relative;
      }
      .img {
        width: 30px;
        height: 30px;
        margin: 0 5px;
        border-radius: 50%;
      }
    }
  }
  .messageInput {
    width: 600px;
    margin-top: 10px;
    max-height: 200px;
  }
}
.infoLeft {
  display: flex;
  justify-content: flex-start;
}
.infoRight {
  display: flex;
  justify-content: flex-end;
}
.infoHalf {
  width: 50%;
}
.infoHalfLeft {
  display: flex;
  justify-content: flex-start;
}
.infoHalfRight {
  display: flex;
  justify-content: flex-end;
}
.mt10 {
  margin-top: 10px;
}
.item_info {
  width: 100%;
  white-space: normal;
}
.delete_msg {
  background-color: white !important;
  font-size: 12px;
  color: #9EA7B4;
}
.withdrawClass {
  cursor: pointer;
}
.workerBox {
  width: 600px;
  height: 345px;
  border: 1px solid #e3e3e3;
  padding: 10px;
}
.mainThread {
  width: 100%;
  padding: 16px 0;
}
.subThread {
  width: 100%;
  height: 60px;
  border: 1px solid greenyellow;
  padding: 10px 0;
}
.asyncAction {
  width: 100%;
  height: 90px;
  border: 1px solid #52e8fc;
  padding: 10px 0;
}
</style>
<style>
.msgHtml p{
  word-wrap: break-word;
}
</style>